package com.ahdms.es.ocsp;

import com.ahdms.es.gm.constant.IKIObjectIdentifiers;
import com.ahdms.es.util.CalculateHashUtils;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.ocsp.*;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.operator.ContentSigner;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * ocsp请求(OCSPRequest)构造工具类
 * @Title 
 * @Description 
 * @Copyright <p>Copyright (c) 2015</p>
 * @Company <p>迪曼森标识技术有限公司Co., Ltd.</p>
 * @author hexin
 * @version 1.0
 * @修改记录
 * @修改序号，修改日期，修改人，修改内容
 */
public class OCSPRequestBuilder {
    private OCSPRequest ocspRequest;  //ocsp请求
    private TBSRequest tbsRequest;    //ocsp请求数据结构体
    private Certificate signCert;     //ocsp请求签名证书
    private ExtensionsGenerator requestExtensions;//ocsp请求扩展项

    /**
     * 构造单个或多个证书状态请求(带签名)
     * @创建人 hexin
     * @创建时间 2017年8月8日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param reqCerts 向ocsp服务器请求的证书集合
     * @param signCert 对请求数据签名的请求者签名证书
     */
    public OCSPRequestBuilder(List<Certificate> reqCerts, Certificate signCert , Certificate pkm) {
        if(null == reqCerts || reqCerts.size() == 0){
        	throw new NullPointerException("OCSPRequestBuilder reqCertificates null");
        }else if(null == signCert){
        	throw new NullPointerException("OCSPRequestBuilder signCertificate null");
        }else{
        	this.signCert = signCert;
        	this.tbsRequest = getTBSRequest(reqCerts, signCert,pkm);
        	this.requestExtensions = new ExtensionsGenerator();
        }
    }

    /**
     * 构造单个或多个证书状态请求(不带签名)
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param reqCerts 向ocsp服务器请求的证书集合
     */
    public OCSPRequestBuilder(List<Certificate> reqCerts, Certificate pkm) {
        if(null == reqCerts || reqCerts.size() == 0){
        	throw new NullPointerException("OCSPRequestBuilder reqCertificates null");
        }else{
        	this.tbsRequest = getTBSRequest(reqCerts, null,pkm);
        	this.requestExtensions = new ExtensionsGenerator();
        }
    }
    
    /**
     * 新增ocsp请求扩展项
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param extension ocsp单个扩展项
     * @return
     */
    public OCSPRequestBuilder addExtension(Extension extension){
		requestExtensions.addExtension(extension);
        return this;
    }
    
    /**
     * 构造OCSPRequest请求(带签名)
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param signer 签名数据结构
     * @return
     */
    public OCSPRequest build(ContentSigner signer) throws IOException { 
        if(null == signCert){
        	throw new NullPointerException("signCert no add data");
        }else{
        	if (!requestExtensions.isEmpty()){
        		tbsRequest = new TBSRequest(tbsRequest.getRequestorName(),tbsRequest.getRequestList(),requestExtensions.generate());
        	}
        	ocspRequest = generateFullOCSPRequest(tbsRequest, signer);
        }

        return ocspRequest;
    }

    /**
     * 构造OCSPRequest请求(不带签名)
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     */
    public OCSPRequest build() throws IOException { 
    	
    	if (!requestExtensions.isEmpty()){
    		tbsRequest = new TBSRequest(tbsRequest.getRequestorName(),tbsRequest.getRequestList(),requestExtensions.generate());
    	}
    	ocspRequest = generateFullOCSPRequest(tbsRequest, null);

        return ocspRequest;
    }
    
    /**
     * 获取ocsp请求数据结构体TBSRequest
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param reqCerts 向ocsp服务器请求的证书集合
     * @param signCert 对请求数据签名的请求者签名证书
     * @param pkm 
     * @return
     */
    private TBSRequest getTBSRequest(List<Certificate> reqCerts, Certificate signCert, Certificate pkm){
    	GeneralName requestorName = null;//请求者名称
		if(null!=signCert){
			requestorName = new GeneralName(signCert.getTBSCertificate().getSubject());
		}

		//组装ocsp-Request请求列表
		ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();//请求集合
		for(int i=0;i<reqCerts.size();i++){
			Certificate cert = reqCerts.get(i);
			
			//组装请求证书CertID
			byte[] issuerNameHash = null;
			try {
				issuerNameHash = CalculateHashUtils.sm3Digest(cert.getIssuer().getEncoded());
			} catch (IOException e) {
				e.printStackTrace();
			}
			DERBitString issuerKey = pkm.getTBSCertificate().getSubjectPublicKeyInfo().getPublicKeyData();//颁发者公钥
			byte[] issuerKeyHash = CalculateHashUtils.sm3Digest(issuerKey.getOctets());
			ASN1Integer serialNumber = cert.getSerialNumber();//证书序列号
			AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(IKIObjectIdentifiers.sm_3);//SM3密码杂凑算法标识（无密钥使用）
			CertID reqCertID = new CertID(hashAlgorithm, new DEROctetString(issuerNameHash), 
					new DEROctetString(issuerKeyHash),serialNumber);
			
			//组装单个ocsp请求Request
			Extensions singleExtensions = null;//请求证书扩展项
			Request request = new Request(reqCertID,singleExtensions);
			
			asn1EncodableVector.add(request);
		}
	    DERTaggedObject localDERTaggedObject = new DERTaggedObject(false, 1, new DERSequence(asn1EncodableVector));
	    ASN1Sequence requestList = ASN1Sequence.getInstance(localDERTaggedObject, false);//ocsp请求列表
	
		
		//组装TBSRequest
		Extensions  requestExtensions = null;
		TBSRequest tbsRequest = new TBSRequest(requestorName,requestList,requestExtensions);

    	return tbsRequest;
    }

	/**
	 * 构造最终带签名的OCSPRequest结构体
	 * @创建人 hexin
	 * @创建时间 2017年8月9日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @param tbsRequest
	 * @param signer
	 * @return
	 */
	private OCSPRequest generateFullOCSPRequest(TBSRequest tbsRequest, ContentSigner signer) throws IOException{
		
		Signature optionalSignature = null;//ocsp请求者签名结构
		
		if(null!=signer){
			//获取请求者签名证书链
			ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();
			asn1EncodableVector.add(signCert);
		    DERTaggedObject localDERTaggedObject = new DERTaggedObject(false, 1, new DERSequence(asn1EncodableVector));
		    ASN1Sequence signCerts = ASN1Sequence.getInstance(localDERTaggedObject, false);
			
		    //对TBSRequest签名
			byte[] signature = generateSig(signer, tbsRequest);
			
			//组装ocsp请求者签名结构
			optionalSignature = new Signature(signer.getAlgorithmIdentifier(), new DERBitString(signature), signCerts);
		}

		OCSPRequest ocspRequest = new OCSPRequest(tbsRequest,optionalSignature);
		
		return ocspRequest;
	}
	
	/**
	 * 产生对ocsp请求数据TBSRequest的签名
	 * @创建人 hexin
	 * @创建时间 2017年8月9日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @param signer
	 * @param tbsObj
	 * @return
	 * @throws IOException
	 */
    private byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj)
            throws IOException
        {
            OutputStream sOut = signer.getOutputStream();
            DEROutputStream dOut = new DEROutputStream(sOut);
            dOut.writeObject(tbsObj);
            sOut.close();
            return signer.getSignature();
        }
}
